﻿using System;

namespace Rosetta.Default
{
    public abstract class Converter : AddIn, IConverter
    {
        #region Constructors

        protected Converter([NotNull] string name)
            : base(name, Validate)
        {
        }

        #endregion

        #region Properties

        public Type[] ArgumentTypes
        {
            get
            {
                return ArgumentTypesInternal;
            }
        }

        public Type[] ReturnTypes
        {
            get
            {
                return ReturnTypesInternal;
            }
        }

        #endregion

        #region Public Methods

        [NotNull]
        public Func<T, TResult> Convert<T, TResult>([NotNull] string name)
        {
            return (Func<T, TResult>)this[name];
        }

        [NotNull]
        public Func<T1, T2, TResult> Convert<T1, T2, TResult>([NotNull] string name)
        {
            return (Func<T1, T2, TResult>)this[name];
        }

        [NotNull]
        public Func<T1, T2, T3, TResult> Convert<T1, T2, T3, TResult>([NotNull] string name)
        {
            return (Func<T1, T2, T3, TResult>)this[name];
        }

        [NotNull]
        public Func<T1, T2, T3, T4, TResult> Convert<T1, T2, T3, T4, TResult>([NotNull] string name)
        {
            return (Func<T1, T2, T3, T4, TResult>)this[name];
        }

        #endregion

        #region Protected Methods

        protected void Add<T, TResult>([NotNull] string name, [NotNull] Func<T, TResult> handler, params string[] argumentNames)
        {
            AddMethod(name, handler, argumentNames);
        }

        protected void Add<T1, T2, TResult>([NotNull] string name, [NotNull] Func<T1, T2, TResult> handler, params string[] argumentNames)
        {
            AddMethod(name, handler, argumentNames);
        }

        protected void Add<T1, T2, T3, TResult>([NotNull] string name, [NotNull] Func<T1, T2, T3, TResult> handler, params string[] argumentNames)
        {
            AddMethod(name, handler, argumentNames);
        }

        protected void Add<T1, T2, T3, T4, TResult>([NotNull] string name, [NotNull] Func<T1, T2, T3, T4, TResult> handler, params string[] argumentNames)
        {
            AddMethod(name, handler, argumentNames);
        }

        #endregion

        #region Class Methods

        private static bool Validate([CanBeNull] Delegate handler)
        {
            if (handler != null)
            {
                var type = handler.GetType();

                if (type.IsGenericType)
                {
                    var genericType = type.GetGenericTypeDefinition();
                    return IsConverterFuncType(genericType);
                }
            }

            return false;
        }

        #endregion
    }
}